home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / TPL60N14.ARJ / MAINVARS.PAS < prev    next >
Pascal/Delphi Source File  |  1992-02-27  |  18KB  |  581 lines

  1. {$a+,n-,x-,s-,i-,r-,b-,v-}
  2. unit mainvars;
  3.  
  4. interface
  5. { (C) Apr 19 1983 in BASIC version by:
  6.       Professor W M Kahan,
  7.       567 Evans Hall.
  8.       Electrical Engineering & Computer Science Dept.
  9.       University of California
  10.       Berkeley, California 94720
  11.       USA
  12.  converted to Pascal by:
  13.       B A Wichmann
  14.       National Physical Laboratory
  15.       Teddington Middx
  16.       TW11 OLW
  17.       UK
  18.  further massaging by dmg =
  19.       David M. Gay
  20.       AT&T Bell Labs
  21.       600 Mountain Avenue
  22.       Murray Hill, NJ 07974
  23.  and a couple of bug fixes from dgh = sun!dhough (29 May 1986)
  24.  
  25.  See the article by Richard Karpinski in the February 1985 issue
  26.  of BYTE Magazine.
  27.  
  28.  You may copy this program freely if you acknowledge its source.
  29.  Comments on the Pascal version to NPL or dmg, please.  }
  30.  
  31.    const
  32.       {integer constants}
  33.       NoTrials = 20;
  34.       {Number of tests for commutativity. }
  35.  
  36.    type
  37.       Guard = (Yes, No);
  38.       Rounding = (Chopped, Rounded, Other);
  39.       Message = packed array [1..40] of char;
  40.       WhichOp = packed array [1..14] of char;
  41.       Class = (Flaw, Defect, SeriousDefect, Failure);
  42.  
  43.    var
  44.       {input: text;}
  45.       {Small floating point constants.}
  46.       Zero, { 0.0; }
  47.       Half, { 0.5; }
  48.       One, { 1.0; }
  49.       Two, { 2.0; }
  50.       Three, { 3.0; }
  51.       Four, { 4.0; }
  52.       Five, { 5.0; }
  53.       Eight, { 8.0; }
  54.       Nine, { 9.0; }
  55.       TwentySeven, { 27.0; }
  56.       ThirtyTwo, { 32.0; }
  57.       TwoForty, { 240.0; }
  58.       MinusOne, { -1.0; }
  59.       OneAndHalf: { 1.5; } real;
  60.       MyZero: integer;
  61.       NoTimes, Index: integer;
  62.       ch: char;
  63.       AInverse, A1: real;
  64.       Radix, BInverse, RadixD2, BMinusU2: real;
  65.       C, CInverse: real;
  66.       D, FourD: real;
  67.       E0, E1, Exp2, MinSqrtError: real;
  68.       SqrtError, MaxSqrtError, E9: real;
  69.       Third: real;
  70.       F6, F9: real;
  71.       H, HInverse: real;
  72.       I: integer;
  73.       StickyBit, J: real;
  74.       M, N, N1: real;
  75.       Precision: real;
  76.       Q, Q9: real;
  77.       R, R9: real;
  78.       T, Underflow, S: real;
  79.       OneUlp, UnderflowThreshold, U1, U2: real;
  80.       V, V0, V9: real;
  81.       W: real;
  82.       X, X1, X2, X8, RandomNumber1: real;
  83.       Y, Y1, Y2, RandomNumber2: real;
  84.       Z, PseudoZero, Z1, Z2, Z9: real;
  85.       NoErrors: array [Class] of integer;
  86.       Milestone: integer;
  87.       PageNo: integer;
  88.       GMult, GDiv, GAddSub: Guard;
  89.       RMult, RDiv, RAddSub, RSqrt: Rounding;
  90.       Continue, Break, Done, NotMonot, Monot, AnomolousArithmetic, IEEE,
  91.             SquareRootWrong, UnderflowNotGradual: Boolean;
  92.       { Computed constants. }
  93.       {U1  gap below 1.0, i.e, 1.0-U1 is next number below 1.0 }
  94.       {U2  gap above 1.0, i.e, 1.0+U2 is next number above 1.0 }
  95.  
  96.    procedure Page;
  97.    function Int (X: real): real;
  98.    function Sign (X: real): real;
  99.    procedure Pause;
  100.    procedure Instructions;
  101.    procedure Heading;
  102.    procedure Characteristics;
  103.    procedure History;
  104.    procedure notify(T: WhichOp);
  105.    procedure TestCondition (K: Class; Valid: Boolean; T: Message);
  106.    function Random: real;
  107.    procedure SqrtXMinX (ErrorKind: Class);
  108.    procedure NewD;
  109.    procedure SubRout3750;
  110.    function Power (X, Y: real): real;
  111.    procedure DoesYequalX;
  112.    procedure SubRout3980;
  113.    procedure PrintIfNPositive;
  114.    procedure TestPartialUnderflow;
  115.  
  116. implementation
  117.  
  118.    procedure Page;
  119.      begin
  120.        (* write(#$C) *) {FF in TURBO Pascal} writeln; writeln;
  121.        end;
  122.  
  123.    function Int (X: real): real;
  124.    {  simulates BASIC INT-function, which is defined as:
  125.       INT(X) is the greatest integer value less than or
  126.       equal to X. }
  127.  
  128.  
  129.       function LargeTrunc (X: real): real;
  130.  
  131.          var
  132.             start, acc, y, p: real;
  133.             trunced: integer; (* dgh *)
  134.  
  135.          begin (* LargeTrunc *)
  136.          if abs (X) < maxint then begin
  137.             trunced := trunc(X);
  138.             LargeTrunc := trunced;
  139.             end
  140.          else
  141.             begin
  142.             start := abs (X);
  143.             acc := 0.0;
  144.             repeat
  145.                y := start;
  146.                p := 1.0;
  147.                while y > maxint - 1.0 do
  148.                   begin
  149.                   y := y / Radix;
  150.                   p := p * Radix;
  151.                   end;
  152.                trunced := trunc(y);
  153.                acc := acc + trunced * p;
  154.                start := start - trunced * p;
  155.             until start < 1.0;
  156.             if X < 0.0 then
  157.                LargeTrunc := - acc
  158.             else
  159.                LargeTrunc := acc
  160.             end;
  161.          end (* LargeTrunc *);
  162.  
  163.  
  164.       begin (* Int *)
  165.       if X > 0.0 then
  166.          Int := LargeTrunc (X)
  167.       else if LargeTrunc (X - 0.5) = X then
  168.          Int := X
  169.       else
  170.          Int := LargeTrunc (X) - 1;
  171.       end (* Int *);
  172.  
  173.  
  174.    function Sign (X: real): real;
  175.  
  176.       begin (* Sign *)
  177.       if X < 0.0 then
  178.          Sign := - 1.0
  179.       else
  180.          Sign := + 1.0;
  181.       end (* Sign *);
  182.  
  183.  
  184.    procedure Pause;
  185.  
  186.       var
  187.          ch: char;
  188.  
  189.       begin (* Pause *)
  190.       writeln ('To continue, press any key and newline:');
  191.       readln (input);
  192.       while not eoln (input) do
  193.          read (input, ch);
  194.       Page;
  195.       write ('Diagnosis resumes after milestone no ', Milestone);
  196.       writeln ('               Page: ', PageNo);
  197.       writeln;
  198.       Milestone := Milestone + 1;
  199.       PageNo := PageNo + 1;
  200.       end (* Pause *);
  201.  
  202.  
  203.    procedure Instructions;
  204.  
  205.       begin (* Instructions *)
  206.       writeln ('Lest this program stop prematurely, ',
  207.             'i.e. before displaying');
  208.       writeln ('         "END OF TEST",');
  209.       writeln ('try to persuade the computer NOT to',
  210.             ' terminate execution whenever an');
  211.       writeln ('error like Over/Underflow or Division by Zero occurs,',
  212.             ' but rather');
  213.       writeln ('to persevere with a surrogate value after, ',
  214.             ' perhaps, displaying some');
  215.       writeln ('warning.  If persuasion avails naught, don''t despair'
  216.             , ' but run this');
  217.       writeln ('program anyway to see how many milestones it passes,',
  218.             ' and then');
  219.       writeln ('amend it to make further progress.');
  220.       writeln ('Answer questions with Y, y, N or n',
  221.             ' (unless otherwise indicated).');
  222.       writeln;
  223.       end (* Instructions *);
  224.  
  225.  
  226.    procedure Heading;
  227.  
  228.       begin (* Heading *)
  229.       writeln ('Users are invited to help debug and augment',
  230.             ' this program so it will');
  231.       writeln ('cope with unanticipated and newly uncovered',
  232.             ' arithmetic pathologies.');
  233.       writeln ('Please send suggestions and interesting results to');
  234.       writeln('        Richard Karpinski');
  235.       writeln('        Computer Center U-76');
  236.       writeln('        University of California');
  237.       writeln('        San Francisco, CA 94143-0704, USA');
  238.       writeln;
  239.       writeln('In doing so, please include the following information:');
  240.       writeln('        Version:  10 February 1989');
  241.       writeln('        Computer:'); writeln;
  242.       writeln('        Compiler:'); writeln;
  243.       writeln('        Optimization level:'); writeln;
  244.       writeln('        Other relevant compiler options:'); writeln;
  245.       end (* Heading *);
  246.  
  247.  
  248.    procedure Characteristics;
  249.  
  250.       begin (* Characteristics *)
  251.       writeln (
  252.             'Running this program should reveal these characteristics');
  253.       writeln ('  Radix = 1, 2, 4, 8, 10, 16, 100, 256, or ...');
  254.       writeln ('  Precision = number of significant digits carried.');
  255.       writeln ('  U2 = Radix/Radix^Precision = One Ulp (OneUlpnit in the');
  256.       writeln ('    Last Place) of 1.000xxx .');
  257.       writeln ('  U1 = 1/Radix^Precision = One Ulp of numbers',
  258.             ' a little less than 1.0 .');
  259.       writeln ('  Adequacy of guard digits for Mult., Div., and Subt.');
  260.       writeln ('  Whether arithmetic is chopped, correctly rounded, ',
  261.             'or something else');
  262.       writeln ('    for Mult., Div., Add/Subt. and Sqrt.');
  263.       writeln ('  Whether a Sticky Bit is used correctly for rounding.');
  264.       writeln ('  UnderflowThreshold = an Underflow Threshold.');
  265.       writeln ('  E0 and PseudoZero tell whether underflow is abrupt,',
  266.             ' gradual, or fuzzy.');
  267.       writeln ('  V = an overflow threshold, roughly.');
  268.       writeln ('  V0  tells, roughly, whether Infinity is represented.');
  269.       writeln ('  Comparisions are checked for consistency with',
  270.             ' subtraction');
  271.       writeln ('    and for contamination with pseudo-zeros.');
  272.       writeln ('  Sqrt is tested.  Y^X is not tested.');
  273.       writeln ('  Extra-precise subexpressions are revealed',
  274.             ' but NOT YET tested.');
  275.       writeln ('  Decimal-Binary conversion is NOT YET tested',
  276.             ' for accuracy.');
  277.       end (* Characteristics *);
  278.  
  279.  
  280.    procedure History;
  281.  
  282.       begin (* History *)
  283.       writeln ('The program attempts to discriminate among');
  284.       writeln ('   FLAWs, like lack of a sticky bit,');
  285.       writeln ('   SERIOUS DEFECTs, like lack of a guard digit, and');
  286.       writeln ('   FAILUREs, like 2+2 = 5 .');
  287.       writeln ('Failures may confound subsequent diagnoses.');
  288.       writeln;
  289.       writeln ('The diagnostic capabilities of this program go beyond',
  290.             ' an earlier');
  291.       writeln ('program called "MACHAR", which can be found at the',
  292.             ' end of the');
  293.       writeln ('book  "Software Manual for the Elementary Functions',
  294.             '" (1980) by');
  295.       writeln ('W. J. Cody and W. Waite.  Although both programs',
  296.             ' try to discover');
  297.       writeln ('the Radix, Precision and range (over/underflow',
  298.             ' thresholds)');
  299.       writeln ('of the arithmetic, this program tries to cope',
  300.             ' with a wider variety');
  301.       writeln ('of pathologies, and to say how well the',
  302.             ' arithmetic is implemented.');
  303.       writeln ('BASIC version of this program (C) 1983 by Professor',
  304.             ' W. M. Kahan;');
  305.       writeln ('see source comments for more history.');
  306.       writeln;
  307.       writeln ('The program is based upon a conventional',
  308.             ' radix representation for');
  309.       writeln ('floating-point numbers, but also allows',
  310.             ' logarithmic encoding');
  311.       writeln ('as used by certain early WANG machines.');
  312.       writeln;
  313.       end (* History *);
  314.  
  315.  
  316.    procedure notify(T: WhichOp);
  317.       begin
  318.       writeln('The ', T, ' test is inconsistent;');
  319.       writeln('   PLEASE NOTIFY KARPINSKI !');
  320.       end;
  321.  
  322.    procedure TestCondition (K: Class; Valid: Boolean; T: Message);
  323.  
  324.       begin (* TestCondition *)
  325.       if not Valid then
  326.          begin
  327.          NoErrors [K] := NoErrors [K] + 1;
  328.          case K of
  329.             Flaw:
  330.                write ('FLAW');
  331.             Defect:
  332.                write ('DEFECT');
  333.             SeriousDefect:
  334.                write ('SERIOUS DEFECT');
  335.             Failure:
  336.                write ('FAILURE');
  337.             end;
  338.          writeln (':  ', T);
  339.          end;
  340.       end (* TestCondition *);
  341.  
  342.  
  343.    function Random: real;
  344.  
  345.       var
  346.          X, Y: real;
  347.  
  348.       begin (* Random *)
  349.       X := RandomNumber1 + R9;
  350.       Y := X * X;
  351.       Y := Y * Y;
  352.       X := X * Y;
  353.       Y := X - Int (X);
  354.       RandomNumber1 := Y + X * 0.000005;
  355.       Random := RandomNumber1;
  356.       end (* Random *);
  357.  
  358.  
  359.    procedure SqrtXMinX (ErrorKind: Class);
  360.  
  361.       begin (* SqrtXMinX *)
  362.       SqrtError := ((sqrt (X * X) - X * BInverse) - (X - X * BInverse))
  363.             / OneUlp;
  364.       if SqrtError <> 0 then
  365.          begin
  366.          if SqrtError < MinSqrtError then
  367.             MinSqrtError := SqrtError;
  368.          if SqrtError > MaxSqrtError then
  369.             MaxSqrtError := SqrtError;
  370.          J := J + 1;
  371.          writeln;
  372.          if ErrorKind = SeriousDefect then
  373.             write ('SERIOUS ');
  374.          writeln ('DEFECT:  sqrt( ', X * X, ' - ', X, ') = ');
  375.          writeln (OneUlp * SqrtError, ' instead of correct value 0 .');
  376.          end;
  377.       end (* SqrtXMinX *);
  378.  
  379.  
  380.    procedure NewD;
  381.  
  382.       begin (* NewD *)
  383.       X := Z1 * Q;
  384.       X := Int (Half - X / Radix) * Radix + X;
  385.       Q := (Q - X * Z) / Radix + X * X * (D / Radix);
  386.       Z := Z - Two * X * D;
  387.       if Z <= Zero then
  388.          begin
  389.          Z := - Z;
  390.          Z1 := - Z1;
  391.          end;
  392.       D := Radix * D;
  393.       end (* NewD *);
  394.  
  395.  
  396.    procedure SubRout3750;
  397.  
  398.       begin (* SubRout3750 *)
  399.       if not ((X - Radix < Z2 - Radix) or (X - Z2 > W - Z2)) then
  400.          begin
  401.          I := I + 1;
  402.          X2 := sqrt (X * D);
  403.          Y2 := (X2 - Z2) - (Y - Z2);
  404.          X2 := X8 / (Y - Half);
  405.          X2 := X2 - Half * X2 * X2;
  406.          SqrtError := (Y2 + Half) + (Half - X2);
  407.          if SqrtError < MinSqrtError then
  408.             MinSqrtError := SqrtError;
  409.          SqrtError := Y2 - X2;
  410.          if SqrtError > MaxSqrtError then
  411.             MaxSqrtError := SqrtError;
  412.          end;
  413.       end (* SubRout3750 *);
  414.  
  415.    { Sun version of Power (from dgh)...
  416.    function pow(x, y : real ): real; external c;
  417.    function Power(X, Y: real): real;
  418.       var xx, yy: real;
  419.       begin
  420.          xx := X;
  421.          yy := Y;
  422.          Power := pow(xx,yy);
  423.          end;
  424.    }
  425.  
  426.    function Power (X, Y: real): real;
  427.  
  428.   var z:real;
  429.     iy:integer;
  430.     reciproc:boolean;
  431.       (* Crude power function:  see Cody & Waite for a better one. *)
  432.  
  433.       begin (* Power *)
  434.       if Y = 0.0 then
  435.          Power := 1.0
  436.       else if (X = 0.0) and (Y > 0.0) then
  437.          Power := 0.0
  438.       else if (Y = Int (Y)) AND (Abs(Y) <= MAXINT) THEN BEGIN
  439.          IY := TRUNC (Y);
  440.          reciproc := iy < 0;
  441.          iy := abs (iy);
  442.          z := 1.0;
  443.          while iy > 0 do begin
  444.            if odd(iy) then begin
  445.              z := z*x;
  446.  
  447.            end else begin
  448.            end; {endif}
  449.            iy := iy div 2;
  450.            if iy >0 then begin
  451.               x := sqr (x);
  452.            end else begin
  453.            end; {endif}
  454.  
  455.          end; {endwhile}
  456.          if reciproc then begin
  457.            power := 1 / z;
  458.  
  459.          end else begin
  460.            power := z;
  461.          end {endif}
  462.          end
  463.       else if (X < 0.0) and (Y = Int(Y)) then
  464.          if odd(trunc(Y)) then Power := -exp (Y * ln (-X))
  465.          else Power := exp (Y * ln (-X))
  466.       else
  467.          Power := exp (Y * ln (X));
  468.       end (* Power *);
  469.  
  470.  
  471.    procedure DoesYequalX;
  472.  
  473.       begin (* DoesYequalX *)
  474.       if Y <> X then
  475.          begin
  476.          if N <= 0 then
  477.             begin
  478.             if (Z = Zero) and (Q <= Zero) then write('WARNING') (* dgh: Y --> Z *)
  479.             else begin
  480.                NoErrors [Defect] := NoErrors [Defect] + 1;
  481.                write('DEFECT');
  482.                end;
  483.             writeln (':  computed (', Z, ') ^ (', Q, ') = ');
  484.             writeln (Y, ', which compares unequal to correct ', X, ';'); (* dgh: V --> Y *)
  485.             writeln (' they differ by ', Y - X);
  486.             end;
  487.          N := N + 1;
  488.       { ... count discrepancies. }
  489.          end;
  490.       end (* DoesYequalX *);
  491.  
  492.  
  493.    procedure SubRout3980;
  494.  
  495.       begin (* SubRout3980 *)
  496.       repeat
  497.          Q := I;
  498.          Y := Power (Z, Q);
  499.          DoesYequalX;
  500.          I := I + 1;
  501.          if I <= M then
  502.             X := Z * X;
  503.       until (X >= W) or (I > M);
  504.       end (* SubRout3980 *);
  505.  
  506.  
  507.    procedure PrintIfNPositive;
  508.  
  509.       begin (* PrintIfNPositive *)
  510.       if N > 0 then
  511.          writeln ('Similar discrepancies have occurred ', N, ' times.');
  512.       end (* PrintIfNPositive *);
  513.  
  514.  
  515.    procedure TestPartialUnderflow;
  516.  
  517.       begin (* TestPartialUnderflow *)
  518.       N := 0;
  519.       if Z <> 0 then
  520.          begin
  521.          writeln ('Since comparison denies Z = 0, evaluating');
  522.          writeln ('(Z + Z) / Z should be safe.');
  523.          write ('What the machine gets for (Z + Z) / Z is: ');
  524.          Q9 := (Z + Z) / Z;
  525.          writeln (Q9);
  526.          if (abs (Q9 - Two) < Radix * U2) then
  527.             begin
  528.             write ('This is O.K., provided Over/Underflow');
  529.             writeln (' has NOT just been signaled.');
  530.             end
  531.          else if (Q9 < One) or (Q9 > Two) then
  532.             begin
  533.             N := 1;
  534.             NoErrors [SeriousDefect] := NoErrors [SeriousDefect] + 1;
  535.             writeln ('This is a VERY SERIOUS DEFECT!');
  536.             end
  537.          else
  538.             begin
  539.             N := 1;
  540.             NoErrors [Defect] := NoErrors [Defect] + 1;
  541.             writeln ('This is a DEFECT.');
  542.             end;
  543.          V9 := Z * One;
  544.          RandomNumber1 := V9;
  545.          V9 := One * Z;
  546.          RandomNumber2 := V9;
  547.          V9 := Z / One;
  548.          if (Z = RandomNumber1) and (Z = RandomNumber2)
  549.                and (Z = V9) then
  550.             begin
  551.             if N > 0 then
  552.                Pause
  553.             end
  554.          else
  555.             begin
  556.             N := 1;
  557.             NoErrors [Defect] := NoErrors [Defect] + 1;
  558.             writeln ('DEFECT: What prints as Z = ', Z, 'compares');
  559.             write ('different from        ');
  560.             if not (Z = RandomNumber1) then
  561.                writeln ('Z * 1 = ', RandomNumber1);
  562.             if not ((Z = RandomNumber2)
  563.                   or (RandomNumber2 = RandomNumber1)) then
  564.                writeln ('1 * Z = ', RandomNumber2);
  565.             if not (Z = V9) then
  566.                writeln ('Z / 1 = ', V9);
  567.             if RandomNumber2 <> RandomNumber1 then
  568.                begin
  569.                NoErrors [Defect] := NoErrors [Defect] + 1;
  570.                writeln ('DEFECT   Multiplication does not commute;');
  571.                writeln ('comparison alleges that 1 * Z = ',
  572.                      RandomNumber2);
  573.                writeln ('differs from Z * 1 = ', RandomNumber1);
  574.                end;
  575.             if N > 0 then
  576.                Pause;
  577.             end;
  578.          end;
  579.       end (* TestPartialUnderflow *);
  580. end.
  581.